#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>


#include "pear_base64.h"
#include "log/pear_log.h"
#include "pear_tx_serial.h"
#include "pear_tx_default.h"
#include "utils/pear_curl.h"
#include "utils/pear_dump.h"
#include "crypto/pear_keystore.h"
#include "account/pear_account.h"

#define API_ADDR "http://127.0.0.1:46657"

void usage()
{
    printf("Usage:\n"
           "txcli --key_path <key_path> --recv_addr <recv_addr> --recv_amot <recv_amot> \n");
    return;
}

int main(int argc, char *argv[])
{
    char  c         = '?';
    char *body      = NULL;
    char *resp      = NULL;
    char *key_path  = NULL;
    char *recv_addr = NULL;
    char *recv_amot = NULL;

    pr_tx_t    tx;
    pr_key_t  *key  = NULL;
    pr_sign_t  sign;

    int option_index = 0;

    static struct option long_options[] = {
        {
            "key_path",
            required_argument,
            0,
            0
        },
        {
            "recv_addr",
            required_argument,
            0,
            0
        },
        {
            "recv_amot",
            required_argument,
            0,
            0
        },
        {
            0,
            0,
            0,
            0
        }
    };

    opterr = 0;

    while ((c = getopt_long(argc, argv, "h", long_options, &option_index)) != -1)
    {
        switch (c)
        {
            case 0:
                if (option_index == 0)
                {
                    key_path = optarg;
                }
                else if (option_index == 1)
                {
                    recv_addr = optarg;
                }
                else if (option_index == 2)
                {
                    recv_amot = optarg;
                }
                break;

            case 'h':
                usage();
                exit(EXIT_SUCCESS);
                break;

            case '?':
                printf("Unkonw Option: %s\n", optarg);
                opterr = 1;
                break;
        }
    }

    if (opterr)
    {
        usage();
        exit(EXIT_SUCCESS);
    }

    if (key_path == NULL || recv_addr == NULL || recv_amot == NULL)
    {
        usage();
        exit(-1);
    }

    /*
     * Check Address
     */
    if (strlen(recv_addr) != sizeof(pr_addr_t) * 2)
    {
        printf("recv address format error\n");
        printf("recv addr: %ld  sizeof: %ld\n", strlen(recv_addr), sizeof(pr_addr_t) * 2);
        exit(-1);
    }


    /*
     * Buffer Init
     */
    body = (char *) malloc(sizeof(tx) * 2 + 1);
    if (body == NULL)
    {
        printf("malloc body error\n");
    }

    resp = (char *) malloc(1024);
    if (resp == NULL)
    {
        printf("malloc resp error\n");
    }

    memset(resp, 0x00, 1024);
    memset(&tx,  0x00, sizeof(pr_tx_t));
    memset(body, 0x00, sizeof(tx) * 2 + 1);


    /*
     * Get ECC Key
     */
    key = pr_get_keystore(key_path);
    if (key == NULL)
    {
        printf("pr_get_keysotre error\n");
        exit(-1);
    }

    /*
     * Tx Input Init
     */
    pr_hash160(key->pubkey, sizeof(key->pubkey), tx.input.from);
    memcpy(tx.input.key, key->pubkey, sizeof(pr_pubkey_t));
    tx.input.amount   = atoi(recv_amot);
    tx.input.sequence = 0;

    /*
     * Tx Output Init
     */
    pr_hex_decode((char *) &(tx.output.to), recv_addr, strlen(recv_addr));
    tx.output.amount  = tx.input.amount;


    /*
     * Tx Input Sign Init
     */
    pr_sign((char *)&tx, sizeof(tx), &sign, &key->privkey);
    printf("\nsign data: %s\n", pr_hex_encode(resp, (unsigned char *)&(sign.data), sizeof(sign.data)));
    memcpy((char *)&tx.input.sign, (char *)&sign, sizeof(pr_sign_t));


    /*
     * Make Post Request Body
     */

    sprintf(body, "{"
                    "\"jsonrpc\":\"2.0\","
                    "\"id\":\"anything\","
                    "\"method\":\"broadcast_tx_commit\","
                    "\"params\": {"
                        "\"tx\":\"");
    /*
     * Serialize:
     * Base64
     *
     */
    char buf_test[1024] = {0x00};
    printf("\n\nbuf addr: %s\n\n", pr_hex_encode(buf_test, (unsigned char *)&tx, sizeof(pr_tx_t)));
    //pr_Base64encode(body + strlen(body), (const char *)&tx, sizeof(pr_tx_t));
    sprintf(body + strlen(body), "%s", pr_tx_encode(&tx));
    sprintf(body + strlen(body), "\"}}");

    printf("\n\n=============body:=============\n\n");
    printf("%s\n", body);
    printf("\n\n=============body:=============\n\n");

    /*
     * Send Tx to TM
     */

    pr_curl_cmd("POST", API_ADDR, NULL, NULL, body, strlen(body), resp);
    printf("resp :%s\n", resp);

    /*
     *  Query Account 
     */
    pr_acc_ctx_t *acc_ctx = NULL;
    acc_ctx = pr_new_acc_ctx();
    if (acc_ctx == NULL)
    {
        printf("acc_ctx == NULL\n");
    }

    printf("\n================ Query Account ================\n");
    char temp_buf[41] = {0x00};
    pr_account_query(acc_ctx, pr_hex_encode(temp_buf, tx.input.from, sizeof(tx.input.from)));
    pr_account_query(acc_ctx, pr_hex_encode(temp_buf, tx.output.to,  sizeof(tx.output.to)));
    return 0;
}
